home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / GNUUCP_2 / SOURCE / COMPORT.ASM < prev    next >
Assembly Source File  |  1989-07-31  |  20KB  |  597 lines

  1. title IBM PC Communications I/O Routines 
  2. ;
  3. ; @(#) comport.asm    Version hoptoad-1.3    87/03/24
  4. ;
  5. ; Orginal code -- Curt Klinsing
  6. ;
  7. ; Changes and updates -- Copyright (c) 1987 Tim Pozar
  8. ; Anyone can use this code for anything, but it is copyright by Tim
  9. ; and you must leave his copyright in the code.
  10. ;
  11. ; ver: 0
  12. ; rev: 2
  13. ; March 13th 1987
  14. ; This code is in a very early stage and should not be let out.
  15. ; Several other extensive functions are planned as well as changes
  16. ; to the current code.
  17. ;
  18. ; 2/20/87 
  19. ;   Changed segment declarations and function names (eg. _function)
  20. ; to fit Microsoft C 4.0 and linker requirements.
  21. ;
  22. ; FUNCTIONS CHANGED/ADDED --
  23. ; set_tty(port_number)
  24. ;   Function to find current settings of the port and set up serial 
  25. ; port for 'baud' and 'lcbyte', and enable DTR.  This will set up the
  26. ; port number base addressed passed to it (eg. 3F8h) and all functions
  27. ; will use this port until the function is used again. (NOT READY FOR USE)
  28. ;
  29. ; reset_tty()
  30. ;   Function to put the port back into the state it was when it was 
  31. ; first found by set_tty().  If set_tty() was not called it will not 
  32. ; change the settings of the port. (NOT READY FOR USE)
  33. ;
  34. ; 3/13/87
  35. ; get_msr()
  36. ;   Function to read (get) the byte located in the Modem Status 
  37. ; Register (3FEh).  The table below describes the byte returned.
  38. ;   bit  description
  39. ;    0   Delta Clear to Send (DCTS)
  40. ;        Indicates that the !CTS input to the chip has changed state
  41. ;        since the last time it was read by the processor.
  42. ;    1   Delta Data Set Ready (DDSR)
  43. ;        Indicates that the !DRS input to the chip has changed since 
  44. ;        last time it was read by the processor.
  45. ;    2   Trailing Edge Ring Indicator (TERI)
  46. ;        Indicates that the !RI input to the chip has changed from
  47. ;        an on (logical 1) to an off (logical 0) condition.
  48. ;    3   Delta Rx Line Signal detect (DRLSD)
  49. ;        Indicates that the !RLSD input to the chip has changed state.
  50. ; NOTE: Whenever bit 0, 1, 2, or 3 is set to a logical 1, a modem status
  51. ;       interrupt is generated.
  52. ;
  53. ;    4   Clear to Send (CTS)
  54. ;        This bit is the complement of the clear to send (!CTS) input.
  55. ;        If bit 4 (LOOP) of the MCR is set to a logical 1, this is 
  56. ;        equivalent to RTS in the MCR.
  57. ;    5   Data Set Ready (DSR)
  58. ;        This bit is the complement of the data set ready (!DSR) input.
  59. ;        If bit 4 (LOOP) of the MCR is set to a logical 1, this is 
  60. ;        equivalent to DTR in the MCR.
  61. ;    6   Ring Indicator (RI)
  62. ;        This bit is the complement of the ring indicator (!RI) input.
  63. ;        If bit 4 (LOOP) of the MCR is set to a logical 1, this is 
  64. ;        equivalent to OUT 1 in the MCR.
  65. ;    7   Receive Line Signal Detect (RLSD).
  66. ;        This bit is the complement of the received line signal detect
  67. ;        (!RLSD) input. If bit 4 (LOOP) of the MCR is set to a logical 1,
  68. ;        this is equivalent to OUT 2 in the MCR.
  69. ;
  70. ;   Currently this driver is set up for COM1 (3f8h).
  71. ;   If you are using the interupt driven buffer, take out the code 
  72. ; that enables the DTR so that it doesn't get raised until the vectors
  73. ; are initilized. 
  74. ;
  75.  
  76. _TEXT   SEGMENT BYTE PUBLIC 'CODE'
  77. _TEXT   ENDS
  78. _DATA   SEGMENT BYTE PUBLIC 'DATA'
  79. _DATA   ENDS
  80. CONST   SEGMENT BYTE PUBLIC 'CONST'
  81. CONST   ENDS
  82. _BBS    SEGMENT BYTE PUBLIC 'BBS'
  83. _BBS    ENDS
  84.  
  85. DGROUP  GROUP   CONST, _BBS, _DATA
  86.       ASSUME    CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
  87.  
  88. _TEXT      SEGMENT
  89. ;
  90. ;A set of Lattice C and MSC callable functions to support
  91. ;interrupt driven character I/O on the  IBM PC. Input
  92. ;is buffered, output is polled.
  93. ;
  94. ;added functions (TMP) --
  95. public  _set_tty        ;find current settings, and initialize 
  96.                         ;comm port to 8 bits and set DTR
  97. public  _reset_tty      ;reset to settings that set_tty() found
  98. public  _get_msr        ;get MSR byte from port.
  99. ;
  100. ;original functions --
  101. public  _init_comm      ;initialize the comm port interupts,
  102. public  _uninit_comm    ;remove initialization,
  103. public  _set_xoff       ;enable/disable XON/XOFF,
  104. public  _get_xoff       ;read XON/XOFF state,
  105. public  _rcvd_xoff      ;returns true if XOFF rcvd,
  106. public  _sent_xoff      ;true if XOFF sent,
  107. public  _inp_cnt        ;returns count of rcv chars,
  108. public  _inp_char       ;get one char from buffer,
  109. public  _inp_flush      ;flush input buffer,
  110. public  _outp_char      ;output a character,
  111. ;
  112. ;A better description can be found in the comment
  113. ;block  in each function.
  114. ;
  115. ;       assume  cs:pgroup
  116. ;
  117. FALSE   EQU     0
  118. TRUE    EQU     NOT FALSE
  119. ;
  120. BASE    EQU     03F8H   ;BASE FOR SERIAL BOARD
  121. ;
  122. LCR        equ     BASE+3  ; Line control register
  123. IER     equ     BASE+1  ; Interrup Enable Register
  124. MCR     EQU     BASE+4  ;modem control register
  125. MDMSTA  EQU     BASE+5  ;line status register
  126. MDMMSR  EQU     BASE+6  ;modem status register
  127. MDMBAD  EQU     BASE    ;lsb baud resgister
  128. EnblDRdy equ    01H     ; enable 'data-ready' interrupt bit
  129. IntCtlr  EQU    21H     ;OCW 1 FOR 8259 CONTROLLER
  130. EnblIRQ4 EQU    0EFH    ;Enable COMMUNICATIONS (IRQ4)
  131. dataport EQU    BASE    ;transmit/receive data port
  132. MaskIRQ4 EQU    10H     ;BIT TO DISABLE COMM INTERRUPT (IRQ4)
  133.  
  134. MDMCD   EQU     80H     ;mask for carrier dectect
  135. SETBAU  EQU     80H     ;code for Divisor Latch Access Bit
  136. MDMTBE  EQU     20H     ;8250 tbe flag
  137. MDMBRK  EQU     40H     ;command code for 8250 break
  138. LINMOD  EQU     03H     ;line mode=8 bit, no parity
  139. MDMMOD  EQU     0BH     ;modem mode = DTR and RTS HIGH
  140. STOP2   EQU     04H     ;BIT FOR TWO STOP BITS IF BAUD<300
  141. RS8259  EQU     20H     ;OCW 3 FOR 8259
  142. RSTINT  EQU     64H     ;SPECIFIC EOI FOR COMM INTERRUPT 
  143. XOFF    EQU     13H     ;XOFF character
  144. XON     EQU     11H     ;XON character
  145. ;
  146. ;       MISCELLANEOUS EQUATES
  147. ;
  148. CR      EQU     13
  149. LF      EQU     10
  150. DosCall EQU     33      ;INTERRUPT NUMBER FOR DOS CALL  
  151. CNSTAT  EQU     11      ;FUNCTION NUMBER FOR CONSOLE STATUS
  152. CNIN    EQU     1       ;FUNCTION NUMBER FOR CONSOLE INPUT
  153. BUFSIZ  EQU     512     ;Max NUMBER OF CHARS
  154. SetIntVect  EQU 25H     ;SET INTERRUPT VECTOR FUNCTION NUMBER
  155.  
  156. ;
  157. ; Communication parameters --
  158. ;
  159. baud    equ     96      ; 1047 =  110 (are you kidding?)
  160.                         ;  384 =  300
  161.                         ;   96 = 1200
  162.                         ;   48 = 2400
  163.                         ;   24 = 4800
  164.                         ;   12 = 9600
  165. parity  equ     00000b  ;00000 = none
  166.                         ;01000 = odd
  167.                         ;11000 = even
  168. stopbit equ     000b    ;  000 = 1 bit
  169.                         ;  100 = 2 bits
  170. wordlth equ     11b     ;   10 = 7 bits
  171.                         ;   11 = 8 bits
  172. lcbyte  equ     parity+stopbit+wordlth      ;line control byte
  173. div_on  equ     80h     ;divisor latch access bit (DLAB)
  174.  
  175. ;
  176. ;       DUMP BUFFER, COUNT AND POINTER.  
  177. ;
  178. CIRC_BUF DB     BUFSIZ DUP(?)   ;ALLOW 512 MaxIMUM BUFFERED CHARACTERS
  179. BUF_TOP EQU     $ - 1           ;KEEP TRACK OF THE TOP OF THE BUFFER
  180. CIRC_TOP DW     BUF_TOP         ;
  181. ;
  182. CIRC_IN DW      OFFSET CIRC_BUF ;POINTER TO LAST CHAR. PLACED IN BUFFER
  183. CIRC_CUR DW     OFFSET CIRC_BUF ;POINTER TO NEXT CHAR. TO BE RETRIEVED FROM
  184.                                 ; BUFFER
  185. CIRC_CT DW      0               ;COUNT OF CHARACTERS USED IN BUFFER
  186. SNT_XOFF DB     FALSE           ;FLAG TO CHECK IF AN XOFF HAS BEEN SEND
  187. GOT_XOFF  DB    FALSE           ;FLAG TO CHECK IF AN XOFF HAS BEEN RECEIVED
  188. SEE_XOFF  DB    FALSE           ;FLAT TO SEE IF WE ARE INTERESTED IN XON/XOFF
  189. ;
  190. ;
  191. ; set_tty()
  192. ;
  193. _set_tty proc near
  194.         push    bp
  195. ;        mov     dx,mcr
  196. ;        in      al,dx           ; get modem parameters
  197. ;        mov     MCR_BYTE,al     ; save them
  198.         mov     dx,lcr
  199. ;        in      al,dx           ; get line parameters
  200. ;        mov     LCR_BYTE,al     ; save them
  201.         mov     al,div_on
  202.         out     dx,al           ; set 8250 for baud rate selection
  203.         ; can the baud rate divisor be read to save the settings?
  204.         ; if so, stick the code here.
  205.         mov     ax,baud
  206.         mov     dx,mdmbad
  207.         out     dx,al           ; low byte divisor
  208.         mov     al,ah
  209.         inc     dx
  210.         out     dx,al           ; high byte divisor
  211.         mov     dx,lcr
  212.         mov     al,lcbyte
  213.         out     dx,al           ; set line control reg.
  214.         mov     dx,mcr
  215.         in      al,dx
  216.         or      al,mdmmod
  217.         out     dx,al           ; set DTR high
  218. flsh:   mov     dx,dataport
  219.         in      al,dx
  220.         mov     dx,mdmsta
  221.         in      al,dx
  222.         and     al,1
  223.         jnz     flsh
  224.       
  225.         pop     bp
  226.         ret
  227.  
  228. _set_tty endp
  229.  
  230.  
  231. _reset_tty proc near
  232.         push    bp
  233.  
  234.         pop     bp
  235.         ret
  236.  
  237. _reset_tty endp
  238.  
  239. _get_msr proc near
  240.         push    bp
  241.         push    ds              ; save data segment
  242.         push    cs
  243.         pop     ds
  244.  
  245.         xor     ax,ax
  246.         mov     dx,MDMMSR
  247.         in      al,dx
  248.  
  249.         pop     ds
  250.         pop     bp
  251.         ret
  252.  
  253. _get_msr endp
  254.  
  255. ;
  256. ; set_xoff(flag)         Enable (flag != 0) or disable
  257. ;int flag;              (flag == 0) XON/ XOFF protocol
  258. ;                       for the character input stream.
  259. ;If enabled, an XOFF will be sent when  the buffer
  260. ;reaches 3/4 full. NOTE: an XON will not be sent auto-
  261. ;matically. Your program must do it when it sees
  262. ;the _rcvd_xoff() flag,  and ready for more chars.
  263. ;
  264. _set_xoff proc near
  265.         push    bp
  266.         PUSH    DS              ;SAVE DATA SEGMENT
  267.         mov     bx,[bp+6]       
  268.         push    cs
  269.         pop     ds              ; move code seg addr to data seg reg.
  270.         cmp     bx,0
  271.         jnz     to_on
  272.         mov     see_xoff,FALSE
  273.         jmp     done1
  274. to_on:  mov     see_xoff,TRUE
  275. done1:  pop     ds
  276.         pop     bp
  277.         ret
  278. _set_xoff endp
  279. ;
  280. ;flag = get_xoff()      Returns the current setting
  281. ;                       of the XON/ XOFF flag set
  282. ;by set_xoff(), above.
  283. ;
  284. _get_xoff proc near
  285.         push    bp
  286.         push    ds              ; save data reg
  287.         push    cs
  288.         pop     ds              ; move code seg addr to data seg reg.
  289.         xor     ax,ax
  290.         mov     al,see_xoff
  291.         pop     ds
  292.         pop     bp
  293.         ret
  294. _get_xoff endp
  295. ;
  296. ;flag = sent_xoff();    Returns true if an XOFF
  297. ;                       character was sent, indicating
  298. ;the receive buffer is  3/4 full.
  299. ;
  300. _sent_xoff proc  near
  301.         push    bp
  302.         push    ds              ; save data reg
  303.         push    cs
  304.         pop     ds              ; move code seg addr to data seg reg.
  305.         xor     ax,ax
  306.         mov     al,snt_xoff
  307.         pop     ds
  308.         pop     bp
  309.         ret
  310. _sent_xoff endp
  311. ;
  312. ; rcvd_xoff()            Returns true if an XOFF was
  313. ;                       received; will return false as
  314. ;soon as an XON is received. Does not effect data output,
  315. ;only indicates the above. (Obviously useless for binary
  316. ;data.)
  317. ;
  318. _rcvd_xoff proc  near
  319.         push    bp
  320.         push    ds              ; save data reg
  321.         push    cs
  322.         pop     ds              ; move code seg addr to data seg reg.
  323.         xor     ax,ax
  324.         mov     al,got_xoff
  325.         pop     ds              ; restore data reg
  326.         pop     bp
  327.         ret
  328. _rcvd_xoff endp
  329. ;
  330. ;count = inp_cnt()       Returns the number of characters
  331. ;                       available in the input buffer.
  332. ;
  333.  
  334. _inp_cnt proc near       
  335.         push    bp
  336.         push    ds              ; save data segment
  337.         push    cs
  338.         pop     ds              ; move code seg addr to data seg reg
  339.         mov     ax,circ_ct
  340.         pop     ds
  341.         pop     bp
  342.         ret
  343. _inp_cnt endp
  344. ;
  345. ; inp_flush()    Flush the input buffer.
  346. ;
  347. _inp_flush proc  near    
  348.         push    bp
  349.         push    ds              ; save data reg
  350.         push    cs
  351.         pop     ds              ; move code seg addr to data seg reg.
  352.         mov     bx,offset circ_buf
  353.         mov     circ_in,bx      
  354.         mov     circ_cur,bx
  355.         xor     ax,ax
  356.         mov     circ_ct,ax
  357.         pop     ds
  358.         pop     bp
  359.         ret
  360. _inp_flush endp
  361.  
  362. ; --------- Init -----------------------------------
  363. ; Program initialization:
  364. ;   --  Set up vector for RS232 interrupt (0CH)
  365. ;   --  Enbl IRQ4
  366. ;   --  Enbl RS232 interrupt on data ready
  367. ;
  368. ; ---------------------------------------------------
  369.  
  370. _init_comm proc  near
  371.         push    bp
  372.         cli
  373.  
  374. ;  ---- Set up  INT x'0C' for IRQ4
  375.  
  376.         push    ds
  377.         push    cs
  378.         pop     ds              ;cs to ds
  379.         mov     dx,offset IntHdlr ;relative adddres of interrupt handler
  380.         mov     al,0cH          ;interrupt number for comm.
  381.         mov     ah,SetIntVect   ;function number for setting int vector
  382.         int     DosCall         ;set interrupt in 8086 table
  383.         pop     ds              ;restore DS
  384.  
  385. ;  ---- Enbl IRQ4 on 8259 interrupt controller
  386.  
  387.         cli
  388.  
  389.         in      al,IntCtlr      ; get current masks 
  390.         and     al,EnblIRQ4     ; Reset IRQ4 mask
  391.         out     IntCtlr,al      ; And restore to IMR
  392.  
  393. ;  ---   Enbl 8250 data ready interrupt
  394.  
  395.         mov     dx,LCR          ; DX ==> LCR
  396.         in      al,dx           ; Reset DLAB for IER access
  397.         and     al,7FH
  398.         out     dx,al
  399.         mov     dx,IER          ; Interrupt Enbl Register
  400.         mov     al,EnblDRdy     ; Enable 'data-ready' interrupt
  401.         out     dx,al
  402.  
  403. ;  ---   Enbl OUT2 on 8250
  404.  
  405.         mov     dx,MCR          ; modem control register        
  406.         in      al,dx           ; Enable OUT2
  407.         or      al,08h            ; find out what is in there and
  408.         out     dx,al            ; enable the DTR
  409.  
  410.         sti
  411.  
  412.         pop     bp
  413.         ret
  414. _init_comm endp
  415. ;
  416. ; uninit_comm()          Removes the interrupt structure
  417. ;                       installed by _init_comm(). Must be
  418. ;done before passing control to the DOS, else chars received
  419. ;will be stored into the next program loaded!
  420. ;
  421. _uninit_comm proc near
  422.         push    bp
  423. ; ---   Disable IRQ4 on 8259
  424.  
  425.         cli
  426.         in      al,IntCtlr      ;GET OCW1 FROM 8259
  427.         or      al,MaskIRQ4     ;DISABLE COMMUNICATIONS INTERRUPT
  428.         out     IntCtlr,al
  429.  
  430. ; ---   Disable 8250 data ready interrupt
  431.         
  432.         mov     dx,LCR          ; DX ==> LCR
  433.         in      al,dx           ; Reset DLAB for IER access
  434.         and     al,7FH
  435.         out     dx,al
  436.         mov     dx,IER          ; Interrupt Enbl Register
  437.         mov     al,0            ; Disable all 8250 interrupts
  438.         out     dx,al
  439.  
  440. ;  ---   Disable OUT2 on 8250
  441.  
  442.         mov     dx,MCR          ; modem control register        
  443.         mov     al,0            ; Disable OUT2
  444.         out     dx,al
  445.  
  446.         sti
  447.         pop     bp
  448.         ret
  449. _uninit_comm endp
  450. ;
  451. ;char  inp_char()      Return a character from the input
  452. ;                      buffer. Assumes you have called
  453. ;inp_cnt() to see if theres any characters to get.
  454. ;
  455. _inp_char proc near      
  456.         push    bp
  457.         push    ds              ; save data reg
  458.         push    cs
  459.         pop     ds              ; move code seg addr to data seg reg.
  460.         mov     bx,circ_cur
  461.         xor     ax,ax
  462.         mov     al,[bx]         ;get next char from circ_buf
  463.         DEC     circ_ct         ;decrement circ_buf COUNT
  464.         CMP     bx,circ_top     ;ARE WE AT THE TOP OF THE circ_buf?
  465.         JZ      reset_cur       ;JUMP IF SO
  466.         INC     bx              ;ELSE, BUMP PTR
  467.         JMP SHORT upd_cur
  468. reset_cur:
  469.         mov     bx,OFFSET circ_buf      ;RESET circ_in TO BOTTOM OF BUF.
  470. upd_cur:
  471.         mov     circ_cur,bx             ;SAVE NEW PTR
  472.         xor     cx,cx
  473.         mov     cl,see_xoff     ;check if interested in xon/xoff
  474.         cmp     cl,TRUE
  475.         jnz     clnup2          ;not interested, so goto return
  476.         cmp     snt_xoff,TRUE   ;have we sent an xoff?
  477.         jnz     clnup2          ;no, so return
  478.         cmp     circ_ct,80h     ;yes, so see in buf is now emptying
  479.         jg      clnup2          ;not empty enuf to send xon, jump to ret
  480.         mov     snt_xoff,FALSE
  481.         mov     cl,XON
  482.         push    ax              ; save char
  483.         call    comout
  484.         pop     ax
  485. clnup2: pop     DS              ;GET BACK ENTERING DS
  486.         pop     bp
  487.         ret
  488. _inp_char endp
  489. ;
  490. ; outp_char(c)           Output the character to the
  491. ;char c;                serial port. This is not buffered
  492. ;                       or interrupt driven.
  493. ;
  494. _outp_char proc  near
  495.         push    bp
  496.         mov     bp,sp
  497.         mov     cl,[bp+4]
  498.         sti
  499.         call    comout
  500.         pop     bp
  501.         ret
  502. _outp_char endp
  503. ;
  504. ;Local  subroutine: output CL to the port.
  505. ;
  506. comout: mov     dx,MDMSTA       
  507.         in      al,dx           ; get 8250 status
  508.         and     al,MDMTBE       ; check for transmitter ready
  509.         jz      comout          ; jump if not to wait
  510.         mov     al,cl           ; get char to al
  511.         mov     dx,dataport     
  512.         out     dx,al           ; output char to 8251
  513.         ret
  514. ;
  515. ;       RECEIVE INTERRUPT HANDLER (CHANGED TO PLACE CHARACTERS IN A
  516. ;        CIRCULAR circ_buf AND TO SEND AN XOFF IF THE circ_buf IS MORE THAN
  517. ;        3/4 FULL - S.G.)
  518. ;
  519. IntHdlr:
  520.         CLI
  521.         push    cx
  522.         push    dx
  523.         push    bx
  524.         push    ax
  525.         push    ds
  526.         mov     ax,cs           ;get cur code segment
  527.         mov     ds,ax           ;and set it as data segment
  528.         mov     bx,circ_in      ;GET circ_buf IN PTR
  529.         mov     DX,dataport     ;GET DATA PORT NUMBER
  530.         IN      AL,DX           ;GET RECEIVED CHARACTER
  531. ;       push    ax
  532. ;       push    dx   
  533. ;       xor     ax,ax
  534. ;       xor     dx,dx
  535. ;       mov     dl,al
  536. ;       mov     ah,2
  537. ;       int     DosCall
  538. ;       pop     dx
  539. ;       pop     ax
  540.         xor     cx,cx
  541.         mov     cl,see_xoff     ;check if interested in xon/xoff
  542.         cmp     cl,TRUE
  543.         jnz     ck_full         ;not interested goto ck if buf full
  544.         mov     cl,al           ;put char in cl for testing
  545.         and     cl,7fh          ;turn off any parity bits 
  546.         cmp     cl,XOFF         ;see if we got an xoff
  547.         jnz     ck_xon
  548.         mov     got_Xoff,TRUE   ; code for handling xon/xoff from remote
  549.         jmp     clnup
  550. ck_xon: cmp     cl,XON
  551.         jnz     reg_ch
  552.         mov     got_Xoff,FALSE
  553.         jmp     clnup
  554. ;
  555. ;Normal character; not  XON/XOFF, or XON/XOFF disabled.
  556. ;
  557. reg_ch: test    snt_Xoff,TRUE   ;SEE IF sentXoff IS SET
  558.         jnz     ck_full         ;IF SO, DON'T SEND ANOTHER XOFF
  559.         CMP     circ_ct,(BUFSIZ * 3)/4  ;ALLOW BUF TO BECOME 3/4 FULL BEFORE
  560.                                         ; SENDING XOFF
  561.         jb      savch           ;IF IT'S OK, CONTINUE
  562.         push    ax              ;SAVE CHARACTER
  563.         mov     CL,XOFF         ;GET XOFF CHARACTER
  564.         mov     snt_Xoff,TRUE  ;RESET sentXoff
  565.         call    comout          ; AND SEND IT
  566.         pop     ax              ;RETRIEVE CHARACTER
  567.         JMP SHORT savch         ;IF WE'RE HERE, THE circ_buf HAS BUFSIZ-80H
  568.                                 ;  CHARACTERS
  569. ck_full:
  570.         CMP     circ_ct,BUFSIZ  ;SEE IF circ_buf ALREADY FULL
  571.         JZ      clnup           ; JUMP IF SO, DO NOT PLACE CHARACTER IN BFR
  572. savch:                          
  573.         mov     [bx],AL         ;SAVE NEW CHARACTER IN circ_buf
  574.         inc     circ_ct         ;BUMP circ_buf COUNT
  575.         CMP     bx,circ_top     ;ARE WE AT THE TOP OF THE circ_buf?
  576.         JZ      reset_in        ;JUMP IF SO
  577.         inc     bx              ;ELSE, BUMP PTR
  578.         JMP SHORT into_buf
  579. reset_in:
  580.         mov     bx,OFFSET circ_buf      ;RESET circ_in TO BOTTOM OF BUF.
  581. into_buf:
  582.         mov     circ_in,bx              ;SAVE NEW PTR
  583. clnup:
  584.         mov     AL,RSTINT
  585.         OUT     RS8259,AL       ;ISSUE SPECIFIC EOI FOR 8259
  586.         pop     ds              ;GET BACK ENTERING DS
  587.         pop     ax
  588.         pop     bx
  589.         pop     dx
  590.         pop     cx
  591.         sti
  592.         iret
  593.  
  594. _TEXT   ENDS
  595.  
  596. end
  597.